home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume22 / mailclean / part01 next >
Encoding:
Text File  |  1991-09-08  |  32.2 KB  |  1,238 lines

  1. Newsgroups: comp.sources.misc
  2. From: Gary Mills <mills@ccu.umanitoba.ca>
  3. Subject:  v22i097:  mailclean - Unix mail spool management package, Part01/01
  4. Message-ID: <1991Sep6.040355.13740@sparky.IMD.Sterling.COM>
  5. X-Md4-Signature: e87929cf3c1d83b3c4c7ccaebb79fe5c
  6. Date: Fri, 6 Sep 1991 04:03:55 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: Gary Mills <mills@ccu.umanitoba.ca>
  10. Posting-number: Volume 22, Issue 97
  11. Archive-name: mailclean/part01
  12. Environment: SunOS
  13.  
  14. This is the mailclean package and is described below in more detail in
  15. the README and the man pages.  Its purpose is to exercise control over 
  16. the disk space used for the mail spool.  I investigated the feasiblity 
  17. of using the Berkeley disk quota for this purpose, and determined that 
  18. it was not suitable.  Mailclean is a practical alternative.  It's 
  19. designed to control the size of user's mailboxes in a nice way, warning 
  20. them before action may be taken, and notifying them afterwards.  Any 
  21. administrator with a reasonable knowledge of the mail system should 
  22. be able to install and configure it.
  23.  
  24. Mailclean can also be retreived via anonymous ftp from ccu.umanitoba.ca 
  25. as /pub/mailclean.tar.Z.   It has only run on SunOS so far, but I wrote
  26. it to be portable. It should be usable on any Unix system that uses the
  27. normal Unix mail. I am the author of the  mailclean package and I place 
  28. no restrictions on it,  although I would like to know if others make 
  29. changes to it.  I will integrate patches if people send them to me.
  30.  
  31. -Gary Mills-         -Networking Group-          -U of M Computer Services-
  32. ==================
  33. #! /bin/sh
  34. # This is a shell archive, meaning:
  35. # 1. Remove everything above the #! /bin/sh line.
  36. # 2. Save the resulting text in a file.
  37. # 3. Execute the file with /bin/sh (not csh) to create:
  38. #    README
  39. #    Makefile
  40. #    defs.h
  41. #    mailclean.c
  42. #    mailsize.c
  43. #    mailclean.8
  44. #    mailsize.1
  45. #    policy
  46. #    trunc.msg
  47. # This archive created: Wed Sep  4 21:37:48 CDT 1991
  48. # By:    mills (Gary Mills)
  49. export PATH; PATH=/bin:/usr/bin:$PATH
  50. echo shar: "extracting 'README'" '(    1555 characters)'
  51. if test -f 'README'
  52. then
  53.     echo shar: "will not over-write existing file 'README'"
  54. else
  55.     sed 's/^X//' << \SHAR_EOF > 'README'
  56. X
  57. XMailclean and mailsize comprise a mail spool management package for
  58. Xunix.  They restrict the amount of spool space available to users,
  59. Xbut do it in a nicer way than disk quota would do.  They are very
  60. Xconfigurable, taking parameters from a policy file.
  61. X
  62. XMailclean is intended to be run regularly from cron.  It produces a
  63. Xreport on standard output.  It can truncate oversize mailboxes,
  64. Xsaving old mail to a temporary file, and notifying the owner by mail.
  65. XIt does this in a careful manner, using the same locking mechanism
  66. Xas bin/mail and ucb/mail.  It can also remove or report old mailboxes,
  67. Xstray files, or unsafe files in the spool directory.
  68. X
  69. XMailsize is intended to be run by the user during login.  It produces
  70. Xa warning about the size of the mailbox, in the manner of ``quota''
  71. Xor ``quota -v''.  There are several ways to arrange for it to be run
  72. Xduring login.  It can be added to a global profile or login file.
  73. XAlternatively, mailsize can replace ``quota'', either completely,
  74. Xor only as the command invoked by ``login''.
  75. X
  76. XThe policy file, nominally /etc/policy, is a common location for
  77. Xparameters, and is designed to be easily parsed by C programs or
  78. Xshell scripts.  It could be extended for other similar purposes.
  79. X
  80. XThese programs have so far only run under SunOS 4.1.1, but they should
  81. Xbe reasonably portable to other unix mail systems.  If you need to
  82. Xmake source modifications for other systems, please send me the diffs,
  83. Xand I will merge them with my source.
  84. X
  85. XGary Mills <mills@ccu.umanitoba.ca>
  86. XUniversity of Manitoba
  87. XWinnipeg, Canada
  88. X
  89. SHAR_EOF
  90. if test     1555 -ne "`wc -c < 'README'`"
  91. then
  92.     echo shar: "error transmitting 'README'" '(should have been     1555 characters)'
  93. fi
  94. fi
  95. echo shar: "extracting 'Makefile'" '(    1011 characters)'
  96. if test -f 'Makefile'
  97. then
  98.     echo shar: "will not over-write existing file 'Makefile'"
  99. else
  100.     sed 's/^X//' << \SHAR_EOF > 'Makefile'
  101. XSHELL = /bin/sh
  102. XPACKAGE = README Makefile defs.h mailclean.c mailsize.c \
  103. X    mailclean.8 mailsize.1 policy trunc.msg
  104. X
  105. X# the compiler
  106. X#CC = /bin/cc
  107. XCC = /usr/5bin/cc
  108. X
  109. X# compiler flags
  110. X#CFLAGS =
  111. XCFLAGS = '-DPFILE="/usr/local/etc/policy"'
  112. X
  113. X# destinaton for administrative commands
  114. XEBIN = /usr/local/etc
  115. X
  116. X# destination for user commands
  117. XBIN = /usr/local/bin
  118. X
  119. X# man page directory with last char omitted
  120. XMAN = /usr/local/man/man
  121. X
  122. Xall: mailclean mailsize
  123. X
  124. Xmailclean: mailclean.c defs.h Makefile
  125. X    $(CC) $(CFLAGS) -o mailclean mailclean.c
  126. Xmailsize: mailsize.c defs.h Makefile
  127. X    $(CC) $(CFLAGS) -o mailsize mailsize.c
  128. X
  129. Xinstall: mailclean
  130. X    install -c -o bin -g bin -m 0755 mailclean $(EBIN)
  131. X    install -c -o bin -g bin -m 0755 mailsize $(BIN)
  132. X
  133. Xman: mailclean.8 mailsize.1
  134. X    install -c -m 0444 mailclean.8 $(MAN)8/mailclean.8
  135. X    install -c -m 0444 mailsize.1 $(MAN)1/mailsize.1
  136. X
  137. Xclean:
  138. Xclobber: clean
  139. X    -rm -f mailclean mailsize
  140. X
  141. Xshar: $(PACKAGE)
  142. X    shar $(PACKAGE) > mailclean.shar
  143. X
  144. Xtar: $(PACKAGE)
  145. X    tar cf mailclean.tar $(PACKAGE)
  146. SHAR_EOF
  147. if test     1011 -ne "`wc -c < 'Makefile'`"
  148. then
  149.     echo shar: "error transmitting 'Makefile'" '(should have been     1011 characters)'
  150. fi
  151. fi
  152. echo shar: "extracting 'defs.h'" '(     919 characters)'
  153. if test -f 'defs.h'
  154. then
  155.     echo shar: "will not over-write existing file 'defs.h'"
  156. else
  157.     sed 's/^X//' << \SHAR_EOF > 'defs.h'
  158. X/* defs.h: definitions for mailclean and mailsize */
  159. X
  160. X#define VERSION    "version 1.0"
  161. X
  162. X/* policy file */
  163. X#ifndef PFILE
  164. X#define PFILE    "/etc/policy"
  165. X#endif
  166. X
  167. X/* mail spool directory */
  168. X#ifndef SPOOL
  169. X#define SPOOL    "/usr/spool/mail"
  170. X#endif
  171. X
  172. X/* directory for saved old mail */
  173. X#ifndef OLDDIR
  174. X#define OLDDIR    "/var/tmp"
  175. X#endif
  176. X
  177. X/* mail command */
  178. X#define MAILCMD "/bin/mail %s"
  179. X
  180. X/* if invoked with this name, mailsize will run quota */
  181. X#define QNAME    "Quota"
  182. X
  183. X/* path to the real quota command */
  184. X#define QPATH    "/usr/ucb/quota"
  185. X
  186. X#define PLEN    256
  187. X#define FALSE    0
  188. X#define TRUE    1
  189. X
  190. X#define SIZ_TR    0
  191. X#define AGE_RM    1
  192. X#define STR_RM    2
  193. X#define SIZ_RP    3
  194. X#define NRE_RP    4
  195. X#define STR_RP    5
  196. X#define SIZ_MS    6
  197. X#define SIZ_WA    7
  198. X#define STR_SC    8
  199. X
  200. Xstruct pmap {
  201. X    char    *pm_verb;
  202. X    int        pm_case;
  203. X};
  204. X
  205. Xstruct smap {
  206. X    char    *sm_nam;
  207. X    char    *sm_val;
  208. X};
  209. X
  210. Xstruct store {
  211. X    struct store *se_link;
  212. X    char    se_type;
  213. X    char    se_str[1];
  214. X};
  215. X
  216. X/**/
  217. SHAR_EOF
  218. if test      919 -ne "`wc -c < 'defs.h'`"
  219. then
  220.     echo shar: "error transmitting 'defs.h'" '(should have been      919 characters)'
  221. fi
  222. fi
  223. echo shar: "extracting 'mailclean.c'" '(   14403 characters)'
  224. if test -f 'mailclean.c'
  225. then
  226.     echo shar: "will not over-write existing file 'mailclean.c'"
  227. else
  228.     sed 's/^X//' << \SHAR_EOF > 'mailclean.c'
  229. X/* mailclean.c: mail spool cleanup policy enforcer */
  230. X/*     Author: Gary Mills <mills@ccu.umanitoba.ca> */
  231. X
  232. X#include <stdio.h>
  233. X#include <stdlib.h>
  234. X#include <string.h>
  235. X#include <errno.h>
  236. X#include <time.h>
  237. X#include <dirent.h>
  238. X#include <pwd.h>
  239. X#include <ctype.h>
  240. X#include <signal.h>
  241. X#include <utime.h>
  242. X#include <malloc.h>
  243. X#include <sys/types.h>
  244. X#include <sys/stat.h>
  245. X#include <sys/file.h>
  246. X
  247. X#include "defs.h"
  248. X
  249. Xchar    usage[] = "Usage: %s [-y]\n";
  250. Xint siz_tr_high = 0, siz_tr_low = 0;
  251. Xint age_rm_days = 0;
  252. Xint str_rm = FALSE;
  253. Xint siz_rp_high = 0;
  254. Xint nre_rp = FALSE;
  255. Xint str_rp = FALSE;
  256. Xint str_sc = FALSE;
  257. Xint siz_wa_high = 0;
  258. Xchar *siz_ms = NULL;
  259. Xint yopt = FALSE;    /* "yes" option */
  260. Xint intflag = FALSE;
  261. X
  262. Xchar    mbname[9];
  263. Xchar    oldfile[PLEN];
  264. Xchar    highsize[9], lowsize[9], warnsize[9];
  265. Xchar    erline[PLEN];
  266. Xchar    msname[PLEN];
  267. Xchar    *cmdname;
  268. Xlong    curtime;
  269. X
  270. X/* policy subset interpreted here */
  271. Xstruct pmap    policy[] = {
  272. X    { "mail-size-truncate",    SIZ_TR },
  273. X    { "mail-age-remove",    AGE_RM },
  274. X    { "mail-stray-remove",    STR_RM },
  275. X    { "mail-size-report",    SIZ_RP },
  276. X    { "mail-unsafe-report",    NRE_RP },
  277. X    { "mail-stray-report",    STR_RP },
  278. X    { "mail-size-message",    SIZ_MS },
  279. X    { "mail-size-warn",        SIZ_WA },
  280. X    { "mail-stray-script",    STR_SC },
  281. X    { NULL,            0 }
  282. X};
  283. X
  284. X/* symbols for notification message */
  285. Xstruct smap symtab[] = {
  286. X    { "mailbox",    mbname },
  287. X    { "oldfile",    oldfile },
  288. X    { "hsize",        highsize },
  289. X    { "lsize",        lowsize },
  290. X    { "wsize",        warnsize },
  291. X    { "",        "\\" },
  292. X    { NULL,        NULL },
  293. X};
  294. X
  295. Xmain(argc, argv) int argc; char *argv[]; {
  296. X    char    *spool, *op;
  297. X    struct dirent    *curent;
  298. X    struct passwd    *curpass;
  299. X    DIR        *dpt;
  300. X    struct stat    curstat;
  301. X    char    owner[9];
  302. X    int report, size, age, nuid;
  303. X    char        *reason, *action;
  304. X    int        n;
  305. X    extern void    intcatch();
  306. X    extern struct store *savestr();
  307. X
  308. X    /* parse arguments */
  309. X    cmdname = ( cmdname = strrchr(argv[0], '/') ) ? ++cmdname : argv[0];
  310. X    while ( ++argv, --argc > 0 && *argv[0] == '-' ) {
  311. X    for ( op = argv[0] + 1; *op; ++op ) {
  312. X        switch ( *op ) {
  313. X          case 'y':
  314. X        yopt = TRUE;
  315. X        break;
  316. X          default:
  317. X        (void) fprintf(stderr, usage, cmdname);
  318. X        exit(1);
  319. X        }
  320. X    }
  321. X    }
  322. X    if ( argc > 0 ) {
  323. X    (void) fprintf(stderr, usage, cmdname);
  324. X    exit(1);
  325. X    }
  326. X
  327. X    /* initialize */
  328. X    (void) time(&curtime);
  329. X    if ( getpolicy() != 0 )
  330. X      exit(1);
  331. X    prheader();
  332. X    (void) sprintf(highsize, "%d", siz_tr_high);
  333. X    (void) sprintf(lowsize, "%d", siz_tr_low);
  334. X    (void) sprintf(warnsize, "%d", siz_wa_high);
  335. X    spool = SPOOL;
  336. X    if ( signal(SIGHUP, SIG_IGN) != SIG_IGN )
  337. X      (void) signal(SIGHUP, intcatch);
  338. X    if ( signal(SIGINT, SIG_IGN) != SIG_IGN )
  339. X      (void) signal(SIGINT, intcatch);
  340. X    if ( signal(SIGQUIT, SIG_IGN) != SIG_IGN )
  341. X      (void) signal(SIGQUIT, intcatch);
  342. X    (void) signal(SIGTERM, intcatch);
  343. X    (void) umask(0066);
  344. X    if ( chdir(spool) != 0 ) {
  345. X    (void) sprintf(erline, "%s: Cannot chdir to %s", cmdname, spool);
  346. X    perror(erline);
  347. X    exit(1);
  348. X    }
  349. X    if ( ( dpt = opendir(spool) ) == NULL ) {
  350. X    (void) sprintf(erline, "%s: Cannot diropen %s", cmdname, spool);
  351. X    perror(erline);
  352. X    exit(1);
  353. X    }
  354. X
  355. X    /* run through the directory entries */
  356. X    while ( errno = 0, curent = readdir(dpt) ) {
  357. X    if ( intflag ) {
  358. X        (void) fprintf(stderr, "%s: Caught a signal", cmdname);
  359. X        exit(1);
  360. X    }
  361. X
  362. X    /* skip special entries */
  363. X    if ( strcmp(curent->d_name,".") == 0 || strcmp(curent->d_name,"..") == 0 )
  364. X      continue;
  365. X
  366. X    /*collect information */
  367. X    if ( stat(curent->d_name, &curstat) != 0 ) {
  368. X        (void) sprintf(erline, "%s: Cannot stat %s", cmdname, curent->d_name);
  369. X        perror(erline);
  370. X        exit(1);
  371. X    }
  372. X    size = curstat.st_size / 1024L;
  373. X    age = ( curtime - curstat.st_atime ) / ( 24 * 60 * 60 );
  374. X
  375. X    /* skip lock and temp files */
  376. X    if ( ( n = strlen(curent->d_name) ) > 5 && age < 2 &&
  377. X        strcmp(curent->d_name + n - 5, ".lock") == 0 )
  378. X      continue;
  379. X    if ( n > 6 && curstat.st_size == 0 && age < 1 &&
  380. X        istmpnam(curent->d_name + n - 6) )
  381. X      continue;
  382. X    if ( curpass = getpwnam(curent->d_name) ) {
  383. X        nuid = curpass->pw_uid;
  384. X    }
  385. X    else {
  386. X        nuid = -99999;
  387. X    }
  388. X    if ( curpass = getpwuid(curstat.st_uid) ) {
  389. X        (void) strcpy(owner, curpass->pw_name);
  390. X    }
  391. X    else {
  392. X        (void) sprintf(owner, "%d", (int) curstat.st_uid);
  393. X    }
  394. X    report = FALSE;
  395. X    reason = action = "";
  396. X
  397. X    /* classify files, perform action, and report */
  398. X    if ( ( curstat.st_mode & S_IFMT ) != S_IFREG || curstat.st_nlink > 1 ) {
  399. X        reason = "unsafe";
  400. X        if ( nre_rp ) {
  401. X        report = TRUE;
  402. X        }
  403. X    }
  404. X    else if ( curstat.st_uid != nuid ) {
  405. X        reason = "stray";
  406. X        if ( str_rm ) {
  407. X        if ( doremove(curent->d_name) != 0 )
  408. X          exit(1);
  409. X        report = TRUE;
  410. X        action = "removed";
  411. X        }
  412. X        else if ( str_sc ) {
  413. X        if ( savestr('r', curent->d_name) == NULL )
  414. X          exit(1);
  415. X        report = TRUE;
  416. X        action = "scripted";
  417. X        }
  418. X        else if ( str_rp ) {
  419. X        report = TRUE;
  420. X        }
  421. X    }
  422. X    else if ( age > age_rm_days ) {
  423. X        reason = "age";
  424. X        if ( doremove(curent->d_name) != 0 )
  425. X          exit(1);
  426. X        report = TRUE;
  427. X        action = "removed";
  428. X    }
  429. X    else if ( size > siz_tr_high ) {
  430. X        reason = "size";
  431. X        (void) strcpy(mbname, curent->d_name);
  432. X        if ( dotrunc(curent->d_name, &curstat) != 0 )
  433. X          exit(1);
  434. X        report = TRUE;
  435. X        action = "truncated";
  436. X    }
  437. X    else if ( size > siz_rp_high ) {
  438. X        reason = "size";
  439. X        report = TRUE;
  440. X    }
  441. X    if ( report )
  442. X      (void) printf("%-16s%-12s%6d%8d    %-16s%s\n", curent->d_name,
  443. X            owner, size, age, reason, action);
  444. X    }
  445. X    if ( errno ) {
  446. X    (void) sprintf(erline, "%s: Readdir failed", cmdname);
  447. X    perror(erline);
  448. X    exit(1);
  449. X    }
  450. X    (void) closedir(dpt);
  451. X    (void) printf("\nReport completed\n\n");
  452. X    prscript(spool);
  453. X    exit(0);
  454. X    /*NOTREACHED*/
  455. X}
  456. X
  457. X/* getpolicy: interpret the policy file */
  458. Xint getpolicy() {
  459. X    char    pline[PLEN], pverb[PLEN];
  460. X    FILE    *pfp;
  461. X    char    *pfile, *pt;
  462. X    struct pmap    *pp;
  463. X    int        n1, n2;
  464. X
  465. X    pfile = PFILE;
  466. X    if ( ( pfp = fopen(pfile, "r") ) == NULL ) {
  467. X    (void) sprintf(erline, "%s: Cannot open %s", cmdname, pfile);
  468. X    perror(erline);
  469. X    return 1;
  470. X    }
  471. X    else {
  472. X    while ( fgets(pline, PLEN, pfp) ) {
  473. X        if ( ( pt = strchr(pline, '#') ) != NULL )
  474. X          *pt = '\0';
  475. X        if ( sscanf(pline, "%s", pverb) == 1 ) {
  476. X        for ( pp = &policy[0]; pp->pm_verb; ++pp ) {
  477. X            if ( strcmp(pverb, pp->pm_verb) == 0 ) {
  478. X            switch (pp->pm_case) {
  479. X              case SIZ_TR:
  480. X                if ( sscanf(pline, "%*s%d%d", &n1, &n2) == 2 ) {
  481. X                siz_tr_high = n1;
  482. X                siz_tr_low = n2;
  483. X                }
  484. X                break;
  485. X              case AGE_RM:
  486. X                if ( sscanf(pline, "%*s%d", &n1) == 1 ) {
  487. X                age_rm_days = n1;
  488. X                }
  489. X                break;
  490. X              case STR_RM:
  491. X                str_rm = TRUE;
  492. X                break;
  493. X              case SIZ_RP:
  494. X                if ( sscanf(pline, "%*s%d", &n1) == 1 ) {
  495. X                siz_rp_high = n1;
  496. X                }
  497. X                break;
  498. X              case NRE_RP:
  499. X                nre_rp = TRUE;
  500. X                break;
  501. X              case STR_RP:
  502. X                str_rp = TRUE;
  503. X                break;
  504. X              case STR_SC:
  505. X                str_sc = TRUE;
  506. X                break;
  507. X              case SIZ_MS:
  508. X                if ( sscanf(pline, "%*s%s", msname) == 1 ) {
  509. X                siz_ms = msname;
  510. X                }
  511. X                break;
  512. X              case SIZ_WA:
  513. X                if ( sscanf(pline, "%*s%d", &n1) == 1 ) {
  514. X                siz_wa_high = n1;
  515. X                }
  516. X                break;
  517. X            }
  518. X            break;
  519. X            }
  520. X        }
  521. X        }
  522. X    }
  523. X    (void) fclose(pfp);
  524. X    }
  525. X    return 0;
  526. X}
  527. X
  528. X/* prheader: print the report header */
  529. Xprheader() {
  530. X
  531. X    (void) printf("Mail Spool Cleanup Report:\t\t%s\n", ctime(&curtime));
  532. X    (void) printf("\nPolicy in effect:\n");
  533. X    if ( siz_tr_high > 0 )
  534. X      (void) printf("\tTruncate from %d to %d kbytes\n", siz_tr_high, siz_tr_low);
  535. X    if ( siz_ms )
  536. X      (void) printf("\tSend message from %s\n", siz_ms);
  537. X    if ( age_rm_days > 0 )
  538. X      (void) printf("\tRemove older than %d days\n", age_rm_days);
  539. X    if ( str_rm )
  540. X      (void) printf("\tRemove stray files\n");
  541. X    if ( str_sc )
  542. X      (void) printf("\tScript stray files\n");
  543. X    if ( siz_rp_high > 0 )
  544. X      (void) printf("\tReport larger than %d kbytes\n", siz_rp_high);
  545. X    if ( nre_rp )
  546. X      (void) printf("\tReport unsafe files\n");
  547. X    if ( str_rp )
  548. X      (void) printf("\tReport stray files\n");
  549. X    (void) printf("\nMode:");
  550. X    (void) printf( (!yopt) ? " simulated" : " actual");
  551. X    (void) printf("\n\n\n%-16s%-12s%6s%8s    %-16s%s\n\n", "NAME", "OWNER",
  552. X          "SIZE", "AGE", "REASON", "ACTION");
  553. X}
  554. X
  555. X/* doremove: remove a spool file */
  556. Xdoremove(file) char *file; {
  557. X
  558. X    if ( yopt && unlink(file) != 0 ) {
  559. X    (void) sprintf(erline, "%s: Cannot unlink %s", cmdname, file);
  560. X    perror(erline);
  561. X    return 1;
  562. X    }
  563. X    return 0;
  564. X}
  565. X
  566. X/* dotrunc: truncate a spool file */
  567. Xstatic int    serial = 0;
  568. Xstatic char    cset[] =
  569. X  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-+";
  570. X
  571. Xdotrunc(file, st) char *file; struct stat *st; {
  572. X    char    *olddir;
  573. X    char    *p1, *p2;
  574. X    struct utimbuf ut;
  575. X    char    vary[3];
  576. X    char    temfile[PLEN];
  577. X    char    line[PLEN];
  578. X    char    tline[PLEN];
  579. X    char    gatefile[16];
  580. X    char    lockfile[16];
  581. X    char    cline[64];
  582. X    long    len, lim;
  583. X    int        n, rc;
  584. X    FILE    *oldfp, *tmpfp, *mailfp;
  585. X    FILE    *msfp, *pifp;
  586. X    extern FILE    *fmkstemp();
  587. X    extern char    *subst();
  588. X
  589. X    if ( !yopt ) return 0;
  590. X    olddir = OLDDIR;
  591. X
  592. X    /* build file names */
  593. X    vary[0] = cset[ ( serial % ( 64 * 64 ) ) / 64 ];
  594. X    vary[1] = cset[ serial % 64 ];
  595. X    vary[2] = '\0';
  596. X    ++serial;
  597. X    (void) sprintf(oldfile, "%s/%sXXXXXX", olddir, vary);
  598. X    (void) sprintf(temfile, "/tmp/%sXXXXXX", vary);
  599. X    (void) sprintf(gatefile, "%sXXXXXX", vary);
  600. X    (void) sprintf(lockfile, "%s.lock", file);
  601. X
  602. X    /* create file to save old mail */
  603. X    if ( ( oldfp = fmkstemp(oldfile) ) == NULL )
  604. X      return 1;
  605. X    rc = 0;
  606. X
  607. X    /* create temp file */
  608. X    if ( ( tmpfp = fmkstemp(temfile) ) == NULL )
  609. X      rc = 1;
  610. X    if ( !rc ) {
  611. X    (void) unlink(temfile);
  612. X
  613. X    /* create temp file for locking */
  614. X    if ( ( n = mkstemp(gatefile) ) < 0 ) {
  615. X        (void) sprintf(erline, "%s: Cannot create %s", cmdname, gatefile);
  616. X        perror(erline);
  617. X        rc = 1;
  618. X    }
  619. X    if ( !rc ) {
  620. X        (void) close(n);
  621. X        n = 0;
  622. X
  623. X        /* create lock file */
  624. X        while ( link(gatefile, lockfile) != 0 ) {
  625. X        if ( errno != EEXIST || n > 60 ) {
  626. X            (void) sprintf(erline, "%s: Cannot create lock %s",
  627. X                   cmdname, lockfile);
  628. X            perror(erline);
  629. X            rc = 1;
  630. X            break;
  631. X        }
  632. X        (void) sleep(5);
  633. X        n += 5;
  634. X        }
  635. X        (void) unlink(gatefile);
  636. X        if ( !rc ) {
  637. X
  638. X        /* open the mailbox */
  639. X        if ( ( mailfp = fopen(file, "r+") ) == NULL ) {
  640. X            (void) sprintf(erline, "%s: Cannot open %s", cmdname, file);
  641. X            perror(erline);
  642. X            rc = 1;
  643. X        }
  644. X        if ( !rc ) {
  645. X
  646. X            /* lock with flock, too */
  647. X            (void) flock(fileno(mailfp), LOCK_EX);
  648. X            n = 0;
  649. X            len = 0L;
  650. X            lim = st->st_size - (siz_tr_low * 1024);
  651. X
  652. X            /* copy with truncation */
  653. X            while ( fgets(line, PLEN, mailfp) ) {
  654. X            len += strlen(line);
  655. X            if ( n == 0 && len > lim &&
  656. X                strncmp(line, "From ", 5) == 0 )
  657. X                n = 1;
  658. X            if ( n == 0 )
  659. X              (void) fputs(line, oldfp);
  660. X            else
  661. X              (void) fputs(line, tmpfp);
  662. X            }
  663. X            if ( ferror(mailfp) ) {
  664. X            (void) sprintf(erline, "%s: Read failed on %s",
  665. X                       cmdname, file);
  666. X            perror(erline);
  667. X            rc = 1;
  668. X            }
  669. X            if ( !rc ) {
  670. X
  671. X            /* reopen the mailbox */
  672. X            if ( ( mailfp = freopen(file, "w", mailfp) ) == NULL ) {
  673. X                (void) sprintf(erline, "%s: Cannot reopen %s",
  674. X                       cmdname, file);
  675. X                perror(erline);
  676. X                rc = 1;
  677. X            }
  678. X            if ( !rc ) {
  679. X                rewind(tmpfp);
  680. X
  681. X                /* copy the retained mail */
  682. X                while ( fgets(line, PLEN, tmpfp) ) {
  683. X                (void) fputs(line, mailfp);
  684. X                }
  685. X            }
  686. X            }
  687. X
  688. X            /* restore times */
  689. X            ut.actime = st->st_atime;
  690. X            ut.modtime = st->st_mtime;
  691. X            (void) fclose(mailfp);
  692. X            (void) utime(file, &ut);
  693. X        }
  694. X        (void) unlink(lockfile);
  695. X        }
  696. X    }
  697. X    (void) fclose(tmpfp);
  698. X    }
  699. X    (void) fchown(fileno(oldfp), (int) st->st_uid, (int) st->st_gid);
  700. X    (void) fclose(oldfp);
  701. X    if ( !rc && siz_ms ) {
  702. X    (void) sprintf(cline, MAILCMD, file);
  703. X
  704. X    /* open the notification template */
  705. X    if ( ( msfp = fopen(siz_ms, "r") ) == NULL ) {
  706. X        (void) sprintf(erline, "%s: Cannot open %s", cmdname, siz_ms);
  707. X        perror(erline);
  708. X        rc = 1;
  709. X    }
  710. X    if ( !rc ) {
  711. X
  712. X        /* open a pipe to mail */
  713. X        if ( ( pifp = popen(cline, "w") ) == NULL ) {
  714. X        (void) sprintf(erline, "%s: Cannot pipe to %s", cmdname, cline);
  715. X        perror(erline);
  716. X        rc = 1;
  717. X        }
  718. X        if ( !rc ) {
  719. X
  720. X        /* copy with substitutions */
  721. X        while ( fgets(line, PLEN, msfp) ) {
  722. X            p2 = line;
  723. X            while ( p1 = strchr(p2, '\\') ) {
  724. X            if ( p2 = strchr(p1+1, '\\') ) {
  725. X                (void) strcpy(tline, p2+1);
  726. X                *p2 = '\0';
  727. X                (void) strcpy(p1, subst(p1+1));
  728. X                p2 = p1 + strlen(p1);
  729. X                (void) strcat(p1, tline);
  730. X            }
  731. X            else break;
  732. X            }
  733. X            (void) fputs(line, pifp);
  734. X        }
  735. X        (void) pclose(pifp);
  736. X        }
  737. X        (void) fclose(msfp);
  738. X    }
  739. X    }
  740. X    return rc;
  741. X}
  742. X
  743. X/* istmpnam: identify a temporary filename */
  744. Xistmpnam(s) char *s; {
  745. X    int c;
  746. X
  747. X    if ( !isalnum(*s) ) return FALSE;
  748. X    while ( c = *++s )
  749. X      if ( !isdigit(c) ) return FALSE;
  750. X    return TRUE;
  751. X}
  752. X
  753. X/* fmkstemp: create and open a temp file */
  754. XFILE *fmkstemp(s) char *s; {
  755. X    int n;
  756. X    FILE *f;
  757. X
  758. X    if ( ( n = mkstemp(s) ) >= 0 ) {
  759. X    if ( f = fdopen(n, "r+") ) return f;
  760. X    }
  761. X    (void) sprintf(erline, "%s: Cannot create %s", cmdname, s);
  762. X    perror(erline);
  763. X    if ( n >= 0 ) {
  764. X    (void) close(n);
  765. X    (void) unlink(s);
  766. X    }
  767. X    return NULL;
  768. X}
  769. X
  770. X/* intcatch: signal handler */
  771. Xvoid intcatch() {
  772. X
  773. X    intflag = TRUE;
  774. X}
  775. X
  776. X/* subst: substitute value for symbol */
  777. Xchar *subst(s) char *s; {
  778. X    struct smap *sp;
  779. X
  780. X    for ( sp = symtab; sp->sm_nam; ++sp ) {
  781. X    if ( strcmp(s, sp->sm_nam) == 0 )
  782. X      return sp->sm_val;
  783. X    }
  784. X    return "";
  785. X}
  786. X
  787. X/* save a string to allocated memory */
  788. Xstruct store *savestr(t, s) int t; char *s; {
  789. X    struct store *pt;
  790. X    static struct store *prev = NULL, *first = NULL;
  791. X
  792. X    if ( t == '\0' ) return first;
  793. X    if ( pt = (struct store *) malloc(sizeof(struct store) + strlen(s)) ) { 
  794. X    if ( first == NULL ) first = pt;
  795. X    else prev->se_link = pt;
  796. X    prev = pt;
  797. X    pt->se_link = NULL;
  798. X    pt->se_type = t;
  799. X    (void) strcpy(pt->se_str, s);
  800. X    }
  801. X    else {
  802. X    (void) fprintf(stderr, "%s: Memory allocation failed\n", cmdname);
  803. X    }
  804. X    return pt;
  805. X}
  806. X
  807. X/* print script from memory */
  808. Xprscript(sp) char *sp; {
  809. X    struct store *se, *nse;
  810. X    extern struct store *savestr();
  811. X
  812. X    if ( se = savestr('\0', (char *) NULL) ) {
  813. X    (void) printf("------cut here------\n#!/bin/sh\n");
  814. X    do {
  815. X        switch ( se->se_type ) {
  816. X          case 'r':
  817. X        (void) printf("rm -f %s/%s\n", sp, se->se_str);
  818. X        }
  819. X        nse = se->se_link;
  820. X        free(se);
  821. X    }
  822. X    while ( se = nse );
  823. X    (void) printf("#!/end\n");
  824. X    }
  825. X}
  826. X
  827. X/**/
  828. SHAR_EOF
  829. if test    14403 -ne "`wc -c < 'mailclean.c'`"
  830. then
  831.     echo shar: "error transmitting 'mailclean.c'" '(should have been    14403 characters)'
  832. fi
  833. fi
  834. echo shar: "extracting 'mailsize.c'" '(    4072 characters)'
  835. if test -f 'mailsize.c'
  836. then
  837.     echo shar: "will not over-write existing file 'mailsize.c'"
  838. else
  839.     sed 's/^X//' << \SHAR_EOF > 'mailsize.c'
  840. X/* mailsize.c: mail spool cleanup policy display and warning */
  841. X/*    Author: Gary Mills <mills@ccu.umanitoba.ca> */
  842. X
  843. X#include <stdio.h>
  844. X#include <stdlib.h>
  845. X#include <string.h>
  846. X#include <errno.h>
  847. X#include <pwd.h>
  848. X#include <sys/types.h>
  849. X#include <sys/stat.h>
  850. X
  851. X#include "defs.h"
  852. X
  853. Xchar    usage[] = "Usage: %s [-v] [username]\n";
  854. Xint siz_tr_high = 0, siz_tr_low = 0;
  855. Xint siz_wa_high = 0;
  856. Xint vopt = FALSE;    /* "verbose" option */
  857. X
  858. Xchar    erline[PLEN];
  859. Xchar    *cmdname;
  860. X
  861. X/* policy subset interpreted here */
  862. Xstruct pmap    policy[] = {
  863. X    { "mail-size-truncate",    SIZ_TR },
  864. X    { "mail-size-warn",        SIZ_WA },
  865. X    { NULL,            0 }
  866. X};
  867. X
  868. X
  869. Xmain(argc, argv) int argc; char *argv[]; {
  870. X    char    *spool, *op, *qpath;
  871. X    char    **qargv;
  872. X    struct passwd *upass;
  873. X    struct stat    mbstat;
  874. X    char    mailpath[PLEN];
  875. X    int        size, qflag;
  876. X    char    *logname;
  877. X    extern char *getlogin();
  878. X
  879. X    /* parse arguments */
  880. X    cmdname = ( cmdname = strrchr(argv[0], '/') ) ? ++cmdname : argv[0];
  881. X    qflag = ( strcmp(cmdname, QNAME) == 0 );
  882. X    qargv = argv;
  883. X    while ( ++argv, --argc > 0 && *argv[0] == '-' ) {
  884. X    for ( op = argv[0] + 1; *op; ++op ) {
  885. X        switch ( *op ) {
  886. X          case 'v':
  887. X        vopt = TRUE;
  888. X        break;
  889. X          default:
  890. X        (void) fprintf(stderr, usage, cmdname);
  891. X        exit(1);
  892. X        }
  893. X    }
  894. X    }
  895. X    if ( argc > 1 ) {
  896. X    (void) fprintf(stderr, usage, cmdname);
  897. X    exit(1);
  898. X    }
  899. X    logname = NULL;
  900. X    if ( argc == 1 ) {
  901. X    if ( upass = getpwnam(*argv) ) {
  902. X        if ( getuid() == upass->pw_uid || (int) getuid() == 0 ) {
  903. X        logname = *argv;
  904. X        }
  905. X        else {
  906. X        (void) fprintf(stderr, "%s: %s (uid %d): permission denied\n",
  907. X                   cmdname, *argv, upass->pw_uid);
  908. X        exit(1);
  909. X        }
  910. X    }
  911. X    else {
  912. X        (void) fprintf(stderr, "%s: %s: unknown user\n", cmdname, *argv);
  913. X        exit(1);
  914. X    }
  915. X    }
  916. X
  917. X    /* initialize */
  918. X    if ( getpolicy() != 0 )
  919. X      exit(1);
  920. X    if ( logname == NULL && ( logname = getlogin() ) == NULL &&
  921. X    ( logname = getenv("LOGNAME") ) == NULL &&
  922. X    ( logname = getenv("USER") ) == NULL ) {
  923. X    (void) fprintf(stderr, "%s: Cannot get login name\n", cmdname);
  924. X    exit(1);
  925. X    }
  926. X    qpath = QPATH;
  927. X    spool = SPOOL;
  928. X    (void) sprintf(mailpath, "%s/%s", spool, logname);
  929. X
  930. X    /* get size of the mailbox */
  931. X    if ( stat(mailpath, &mbstat) != 0 ) {
  932. X    if ( errno != ENOENT ) {
  933. X        (void) sprintf(erline, "%s: Cannot stat %s", cmdname, mailpath);
  934. X        perror(erline);
  935. X        exit(1);
  936. X    }
  937. X    size = 0;
  938. X    }
  939. X    else {
  940. X    size = mbstat.st_size / 1024L;
  941. X    }
  942. X
  943. X    /* print report */
  944. X    if ( vopt ) {
  945. X    (void) printf("Mailbox size for %s\n", logname);
  946. X    (void) printf("%-20s%12s%12s%12s%12s\n", "Spool", "usage", "limit",
  947. X              "warning", "retain");
  948. X    (void) printf("%-20s%12d%12d%12d%12d\n", spool, size, siz_tr_high,
  949. X              siz_wa_high, siz_tr_low);
  950. X    if ( qflag) (void) putchar('\n');
  951. X    }
  952. X    else if ( size > siz_wa_high ) {
  953. X    (void) printf("Oversize mailbox in %s\n", spool);
  954. X    if ( qflag) (void) putchar('\n');
  955. X    }
  956. X    if ( qflag ) {
  957. X
  958. X    /* run ucb/quota */
  959. X    (void) fflush(stdout);
  960. X    qargv[0] = "quota";
  961. X    (void) execv(qpath, qargv);
  962. X    (void) sprintf(erline, "%s: Cannot exec %s", cmdname, qpath);
  963. X    perror(erline);
  964. X    exit(1);
  965. X    }
  966. X    exit(0);
  967. X    /*NOTREACHED*/
  968. X}
  969. X
  970. X/* getpolicy: interpret the policy file */
  971. Xint getpolicy() {
  972. X    char    pline[PLEN], pverb[PLEN];
  973. X    FILE    *pfp;
  974. X    char    *pfile, *pt;
  975. X    struct pmap    *pp;
  976. X    int        n1, n2;
  977. X
  978. X    pfile = PFILE;
  979. X    if ( ( pfp = fopen(pfile, "r") ) == NULL ) {
  980. X    (void) sprintf(erline, "%s: Cannot open %s", cmdname, pfile);
  981. X    perror(erline);
  982. X    return 1;
  983. X    }
  984. X    else {
  985. X    while ( fgets(pline, PLEN, pfp) ) {
  986. X        if ( ( pt = strchr(pline, '#') ) != NULL )
  987. X          *pt = '\0';
  988. X        if ( sscanf(pline, "%s", pverb) == 1 ) {
  989. X        for ( pp = &policy[0]; pp->pm_verb; ++pp ) {
  990. X            if ( strcmp(pverb, pp->pm_verb) == 0 ) {
  991. X            switch (pp->pm_case) {
  992. X              case SIZ_TR:
  993. X                if ( sscanf(pline, "%*s%d%d", &n1, &n2) == 2 ) {
  994. X                siz_tr_high = n1;
  995. X                siz_tr_low = n2;
  996. X                }
  997. X                break;
  998. X              case SIZ_WA:
  999. X                if ( sscanf(pline, "%*s%d", &n1) == 1 ) {
  1000. X                siz_wa_high = n1;
  1001. X                }
  1002. X                break;
  1003. X            }
  1004. X            break;
  1005. X            }
  1006. X        }
  1007. X        }
  1008. X    }
  1009. X    (void) fclose(pfp);
  1010. X    }
  1011. X    return 0;
  1012. X}
  1013. X
  1014. X/**/
  1015. SHAR_EOF
  1016. if test     4072 -ne "`wc -c < 'mailsize.c'`"
  1017. then
  1018.     echo shar: "error transmitting 'mailsize.c'" '(should have been     4072 characters)'
  1019. fi
  1020. fi
  1021. echo shar: "extracting 'mailclean.8'" '(    2850 characters)'
  1022. if test -f 'mailclean.8'
  1023. then
  1024.     echo shar: "will not over-write existing file 'mailclean.8'"
  1025. else
  1026.     sed 's/^X//' << \SHAR_EOF > 'mailclean.8'
  1027. X.TH MAILCLEAN 8 "24 August 1991"
  1028. X.UC 4
  1029. X.SH NAME
  1030. Xmailclean \- clean up files in the mail spool directory
  1031. X.SH SYNOPSIS
  1032. X.B /usr/etc/mailclean
  1033. X[
  1034. X.B \-y
  1035. X]
  1036. X.SH DESCRIPTION
  1037. X.B mailclean
  1038. Xis intended to be run regularly from cron,
  1039. Xto produce a report on standard output,
  1040. Xand optionally take action against files in the mail spool directory.
  1041. XIt can truncate files that are larger than some limit, saving the old
  1042. Xmail to a temporary file, and notifying the owner by mail.
  1043. XIt can also remove or report on files identified as being old, stray,
  1044. Xor unsafe.
  1045. X.LP
  1046. X.B mailclean
  1047. Xwithout the \-y option only reports the actions it would have taken.
  1048. X.LP
  1049. X.B mailclean
  1050. Xtakes its parameters from a policy file, nominally /etc/policy.
  1051. XThe following statements are interpreted by
  1052. X.B mailclean :
  1053. X.RS
  1054. X.IP "mail-age-remove        DAYS"
  1055. Xremove mailbox files that have been unread for more than DAYS days.
  1056. X.IP "mail-stray-remove"
  1057. Xremove mailbox files identified as strays, meaning that the file name
  1058. Xdoes not correspond to the login name of its owner.
  1059. XThis operation is dangerous because it relies on correct operation of
  1060. Xgetpwnam(3) and the integrity of /etc/passwd and the YP/NIS maps.
  1061. X.IP "mail-stray-script"
  1062. Xprint a shell script to remove stray files, which can be run after
  1063. Xthe report has been examined.
  1064. X.IP "mail-stray-report"
  1065. Xreport mailbox files identified as strays.
  1066. X.IP "mail-unsafe-report"
  1067. Xreport files that are not regular files, or have a link count greater
  1068. Xthan one.
  1069. X.IP "mail-size-truncate    KB1    KB2"
  1070. Xtruncate mailbox files that are larger than KB1 kbytes down to KB2 kbytes,
  1071. Xsaving the old mail to a temporary file.
  1072. X.IP "mail-size-message    FILE-NAME"
  1073. Xwhen a file is truncated, send mail to the mailbox owner, using
  1074. XFILE-NAME as a template.
  1075. XThis file should contain a complete mail message, including headers.
  1076. XVariable names, enclosed in backslashes, will be substituted into
  1077. Xthe message, as follows:
  1078. X.sp
  1079. Xmailbox \- mailbox name
  1080. X.br
  1081. Xoldfile \- old mail file name
  1082. X.br
  1083. Xhsize \- mailbox high size
  1084. X.br
  1085. Xlsize \- mailbox low size
  1086. X.br
  1087. Xwsize \- mailbox warning size
  1088. X.br
  1089. X.IP "mail-size-report    KB"
  1090. Xreport mailbox files larger than KB kbytes.
  1091. X.IP "mail-size-warn        KB"
  1092. X.I mailclean
  1093. Xonly uses this for substution into the mail message, but
  1094. X.I mailsize
  1095. Xwill warn the owner at login time when the mailbox is larger than KB kbytes.
  1096. X.RE
  1097. X.LP
  1098. XRemoval actions take precedence over truncation or scripting.
  1099. XAll actions taken are reported.
  1100. X.SH OPTIONS
  1101. X.TP
  1102. X.B \-y
  1103. Xyes.
  1104. XThis option is required to perform the truncate or remove operations.
  1105. X.SH FILES
  1106. X.PD 0
  1107. X.TP 20
  1108. X.B /etc/policy
  1109. Xmail spool management parameters
  1110. X.PD
  1111. X.SH "SEE ALSO"
  1112. X.BR mail(1),
  1113. X.BR mailsize(1)
  1114. X.SH BUGS
  1115. XMail readers often create temporary files and lock files in the spool
  1116. Xdirectory.
  1117. X.B mailclean
  1118. Xattempts to identify these and ignore them when they are recently-created.
  1119. XUser mailboxes in the format of mktemp(3) may cause confusion.
  1120. SHAR_EOF
  1121. if test     2850 -ne "`wc -c < 'mailclean.8'`"
  1122. then
  1123.     echo shar: "error transmitting 'mailclean.8'" '(should have been     2850 characters)'
  1124. fi
  1125. fi
  1126. echo shar: "extracting 'mailsize.1'" '(     775 characters)'
  1127. if test -f 'mailsize.1'
  1128. then
  1129.     echo shar: "will not over-write existing file 'mailsize.1'"
  1130. else
  1131.     sed 's/^X//' << \SHAR_EOF > 'mailsize.1'
  1132. X.TH MAILSIZE 1 "24 August 1991"
  1133. X.UC 4
  1134. X.SH NAME
  1135. Xmailsize \- display the size of a user's mailbox and the size limits
  1136. X.SH SYNOPSIS
  1137. X.B mailsize
  1138. X[
  1139. X.B \-v
  1140. X] [
  1141. X.I username
  1142. X]
  1143. X.SH DESCRIPTION
  1144. X.B mailsize
  1145. Xdisplays the size of the users' mailbox and the limits imposed by
  1146. Xlocal policy.
  1147. XOnly the super-user may use the optional
  1148. X.I username
  1149. Xargument to view the limits of users' mailboxes.
  1150. X.LP
  1151. X.B mailsize
  1152. Xwithout options displays only a warning
  1153. Xwhen the mailbox size is over the warning limit.
  1154. XWhen invoked as
  1155. X.B Quota ,
  1156. X.B mailsize
  1157. Xwill also run the
  1158. X.B quota
  1159. Xcommand.
  1160. X.SH OPTIONS
  1161. X.TP
  1162. X.B \-v
  1163. XDisplay the size of the mailbox and the limits on its size.
  1164. X.SH FILES
  1165. X.PD 0
  1166. X.TP 20
  1167. X.B /etc/policy
  1168. Xmail spool management parameters
  1169. X.PD
  1170. X.SH "SEE ALSO"
  1171. X.BR mail(1),
  1172. X.BR mailclean(8),
  1173. X.BR quota(1)
  1174. SHAR_EOF
  1175. if test      775 -ne "`wc -c < 'mailsize.1'`"
  1176. then
  1177.     echo shar: "error transmitting 'mailsize.1'" '(should have been      775 characters)'
  1178. fi
  1179. fi
  1180. echo shar: "extracting 'policy'" '(     230 characters)'
  1181. if test -f 'policy'
  1182. then
  1183.     echo shar: "will not over-write existing file 'policy'"
  1184. else
  1185.     sed 's/^X//' << \SHAR_EOF > 'policy'
  1186. X# policy for mailsize and mailclean
  1187. X#
  1188. Xmail-size-report    500
  1189. Xmail-size-warn        750        # user login warning
  1190. Xmail-size-truncate    1000    500
  1191. Xmail-size-message    /usr/local/etc/trunc.msg
  1192. Xmail-age-remove        180
  1193. Xmail-stray-script
  1194. Xmail-unsafe-report
  1195. SHAR_EOF
  1196. if test      230 -ne "`wc -c < 'policy'`"
  1197. then
  1198.     echo shar: "error transmitting 'policy'" '(should have been      230 characters)'
  1199. fi
  1200. fi
  1201. echo shar: "extracting 'trunc.msg'" '(     884 characters)'
  1202. if test -f 'trunc.msg'
  1203. then
  1204.     echo shar: "will not over-write existing file 'trunc.msg'"
  1205. else
  1206.     sed 's/^X//' << \SHAR_EOF > 'trunc.msg'
  1207. XFrom: Mail Spool Cleaner <root@ccu.umanitoba.ca>
  1208. XTo: \mailbox\
  1209. XSubject: Oversize Unix Mailbox
  1210. X
  1211. XIn accord with Computer Services policy, your Unix mailbox file has
  1212. Xbeen truncated because it was over the limit of \hsize\ kbytes.  The
  1213. Xmost recent \lsize\ kbytes (approximately) was retained, but your older
  1214. Xmail was moved to a file \oldfile\.  You can access this mail
  1215. Xwith a command such as ``mail -f \oldfile\'', or you can move it
  1216. Xto your home directory and give it a nicer name with a command like
  1217. X``mv \oldfile\ ~/oldmail''.  If you do nothing, this file will
  1218. Xbe removed a week from now in the normal cleanup of the /var/tmp directory.
  1219. X
  1220. XTo avoid this problem in the future, you could delete unwanted mail
  1221. Xfrom your mailbox and save mail to files in your home directory after
  1222. Xyou have read it.  You will receive a warning as you log in whenever
  1223. Xyour mailbox exceeds \wsize\ kbytes.
  1224. X
  1225. SHAR_EOF
  1226. if test      884 -ne "`wc -c < 'trunc.msg'`"
  1227. then
  1228.     echo shar: "error transmitting 'trunc.msg'" '(should have been      884 characters)'
  1229. fi
  1230. fi
  1231. exit 0
  1232. #    End of shell archive
  1233.  
  1234. -- 
  1235. -Gary Mills-         -Networking Group-          -U of M Computer Services-
  1236.  
  1237. exit 0 # Just in case...
  1238.